#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <fcntl.h>
#include <unistd.h>

#define BUFFER_SIZE 4096
#define NUM_THREADS 4

typedef struct {
    int src_fd;
    int dest_fd;
    off_t offset;
    size_t size;
} thread_data_t;

void *copy_chunk(void *arg) {
    thread_data_t *data = (thread_data_t *)arg;
    char buffer[BUFFER_SIZE];
    ssize_t bytes_read, bytes_written;
    off_t offset = data->offset;
    size_t size = data->size;

    lseek(data->src_fd, offset, SEEK_SET);
    lseek(data->dest_fd, offset, SEEK_SET);

    while (size > 0) {
        size_t chunk_size = size > BUFFER_SIZE ? BUFFER_SIZE : size;
        bytes_read = read(data->src_fd, buffer, chunk_size);
        if (bytes_read <= 0) {
            perror("read");
            pthread_exit(NULL);
        }

        bytes_written = write(data->dest_fd, buffer, bytes_read);
        if (bytes_written != bytes_read) {
            perror("write");
            pthread_exit(NULL);
        }

        size -= bytes_written;
    }

    pthread_exit(NULL);
}

int main() {
    const char *src_path = "1.txt";
    const char *dest_path = "2.txt";
    int src_fd, dest_fd;
    off_t file_size, chunk_size;
    pthread_t threads[NUM_THREADS];
    thread_data_t thread_data[NUM_THREADS];

    src_fd = open(src_path, O_RDONLY);
    if (src_fd < 0) {
        perror("open source file");
        exit(EXIT_FAILURE);
    }

    dest_fd = open(dest_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (dest_fd < 0) {
        perror("open destination file");
        close(src_fd);
        exit(EXIT_FAILURE);
    }

    // Get the file size
    file_size = lseek(src_fd, 0, SEEK_END);
    lseek(src_fd, 0, SEEK_SET);
    lseek(dest_fd, 0, SEEK_SET);

    chunk_size = (file_size + NUM_THREADS - 1) / NUM_THREADS; // Compute chunk size

    for (int i = 0; i < NUM_THREADS; i++) {
        thread_data[i].src_fd = src_fd;
        thread_data[i].dest_fd = dest_fd;
        thread_data[i].offset = i * chunk_size;
        thread_data[i].size = (i + 1) * chunk_size > file_size ? file_size - i * chunk_size : chunk_size;

        if (pthread_create(&threads[i], NULL, copy_chunk, &thread_data[i]) != 0) {
            perror("pthread_create");
            exit(EXIT_FAILURE);
        }
    }

    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }

    close(src_fd);
    close(dest_fd);

    printf("File copy completed.\n");
    return 0;
}
